Используем нейросеть локально

Задача: установить нейросеть на свой ПК, и пообщаться с ней посредством python. Маленькая задачка, часть более глобальной далее (в следующих частях) — дообучить на своих данных, и сделать скрипт отвечающий на вопросы пользователей.

Статья подготовлена на основе следующих источников:

  • https://habr.com/ru/companies/bothub/articles/1019314/

Решение:

Сначала установим оболочку для нейросетей. Например я остановился (в данный момент) на https://gpt4all.io. Там есть инсталляторы для разных ОС. Я пока остановился для Windows. После установки нужно выбрать модель для скачивания, в зависимости от того какое у вас «железо». В моем случае, т.к. памяти достаточно (64ггб оперативы + 32ггб RTX 3060), я выбрал DeepSeek-R1-Distill-Qwen-14B

После загрузки модели, попробовал создать чат, и в принципе модель бодренько стала мне отвечать. Правда во время генерации ответов все ресурсы ушли в «полочку». Но ответы вполне осмысленные:

Далее попытался написать скрипт на python, который непосредственно может цепляться к установленной модели. Для этого необходимо в настройка gpt4all включить соответствующую опцию:

После этого становится доступен api через обычный http. Точки вызовов следующие:

  • http://localhost:4891/v1/models — получить список установленных моделей
  • http://localhost:4891/v1/models/ — получить настройки выбранной модели
  • http://localhost:4891/v1/completions — генерация текста
  • http://localhost:4891/v1/chat/completions — общение в режиме чата

Небольшая сноска. Наш любимый РКН, 21.03.2026 заблокировал часть адресов, среди которых под раздачу попала и установка пакетов через pip install. Я сиё обошел установкой VPN Amnezia. Далее упоминать об этом не буду, и считаю что способ установки пакетов у вас есть.

Ну а дальше простой скрипт:

import requests

# URL, куда отправляем запрос (если вы установили GPT-4All локально)
url = "http://localhost:4891/v1/chat/completions"

headers = {
    "Content-Type": "application/json",
}

data = {
    "model": "DeepSeek-R1-Distill-Qwen-14B",  # Используйте модель, которую поддерживает GPT-4All
    "messages": [{"role": "user", "content": "Сколько будет 2+2?"}],
    "max_tokens": 500,
    "temperature": 0.28
}

response = requests.post(url, headers=headers, json=data)

if response.status_code == 200:
    print(response.json())
else:
    print(response)
    print(f"Ошибка: {response.status_code}")

Результат:

Хм, пользователь спросил «Сколько будет 2+2?» на русском языке. Нужно ответить правильно и понятно.
Проверю: 2 плюс 2 равно 4.

1С: Событие по снятию галочки в фильтре формы списка

Столкнулся с интересной особенностью 1С: если на форме списка присутствуют пользовательские фильтры, и пользователь «включил/выключил» этот фильтр, то нет никакого способа это событие отловить

Единственное решение какое я придумал, это подключение обработчика ожидания при событии на открытие формы вида:

ПодключитьОбработчикОжидания("ПосчитатьИтогиНаКлиенте",3,ложь);

Ну и сам обработчик:

&НаКлиенте 
Функция ПосчитатьИтогиНаКлиенте()
	ПосчитатьИтогиНаСервере();
КонецФункции	
Функция ПосчитатьИтогиНаСервере()
	ВсеЭлементы=СписокВКоллекциюЗначений();
	ЗадолженостьПоУведомлению=0;ОстатокЗадолженности=0;ТекущаяЗадолженость=0;	
	для каждого стр из ВсеЭлементы цикл
		ЗадолженостьПоУведомлению=ЗадолженостьПоУведомлению+стр.ЗадолженостьПоУведомлению;
		ОстатокЗадолженности=ОстатокЗадолженности+стр.ОстатокЗадолженности;
		ТекущаяЗадолженость=ТекущаяЗадолженость+стр.ТекущаяЗадолженость;
	КонецЦикла;	
	элементы.Список.ПодчиненныеЭлементы.ЗадолженостьПоУведомлению.ТекстПодвала=ЗадолженостьПоУведомлению;
	элементы.Список.ПодчиненныеЭлементы.ОстатокЗадолженности.ТекстПодвала=ОстатокЗадолженности;
	элементы.Список.ПодчиненныеЭлементы.ТекущаяЗадолженость.ТекстПодвала=ТекущаяЗадолженость;
КонецФункции

1С: Раскраска строк на форме списка (условное оформление)

Задача: обеспечить раскраску строк по условию на форме списка

Решение: может быть разным, в зависимости от сложности условий и способа вывода данных на форму.

Вариант 1: данные формируются запросом СКД, динамически:

В этом случае заходим во вкладку «Условное оформление» и настраиваем собственно условия:

Вариант 2: данные формируются «как обычно».

В этом случае в свойствах формы ищем реквизит «Условное оформление» и настраиваем по тому-же принципу как и в Варианте 1

Вариант 3: подходит для «сложных» вариантов оформления, когда при помощи первого и второго варианта, нужного эффекта добиться не удалось. В свойстве «ПриОткрытии» размещаем код вида:

&НаКлиенте
Процедура УстановитьУсловноеОформлениеДляПоляДатаДоговора()

   // Создание элемента условного оформления
   ЭлементыОформления = СписокПартийДС.УсловноеОформление.Элементы.Добавить();
   ЭлементыОформления.Использование = Истина;

   // Настройка оформляемого поля
   Поля = ЭлементыОформления.Поля.Элементы.Добавить();
   Поля.Использование = Истина;
   Поля.Поле = Новый ПолеКомпоновкиДанных("ДатаДог");
   Поля = ЭлементыОформления.Поля.Элементы.Добавить();
   Поля.Использование = Истина;

   // Создание условия для элемента оформления
   Отбор = ЭлементыОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
   Отбор.Использование = Истина;
   Отбор.ВидСравнения = ВидСравненияКомпоновкиДанных.Больше;
   Отбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ДатаДог");
   Отбор.ПравоеЗначение = ТекущаяДата() + 31557600;

   // Установка цвета оформления
   Оформление = ЭлементыОформления.Оформление;
   Оформление.УстановитьЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ЦветФона"), WebЦвета.ЛососьСветлый);

КонецПроцедуры

1С: Итоги в подвале на форме списка

Если в таблице значений на форме, это штатный функционал, то на форме списка, там где по сути табличный документы, возможно лишь вывести пустую строку подвала. А итоги считать нужно самостоятельно. Описанный способ не претендует на идеальную правильность. Скорее это всего лишь самый простой способ. Есть более красивые способы — при помощи правки СКД динамического списка и т.д. Но я СКД недолюбливаю, потому у меня так.

1. Ставим галочку подвал в свойствах списка

2. На событие «ПриАктивацииСтроки» у списка вешаем следующий код:

&НаСервере
Функция СписокВКоллекциюЗначений()
	//Получаем схема компановки данных (здесь хранится текст запроса)
	Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();	
	//Получаем настройки пользователя (отборы, сортировки и т.п.)
	Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();	
	//Выводим динамический список в таблицу значений
	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных();
	МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , ,Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));	
	ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
	ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);	
	ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
	Результат = ПроцессорВывода.Вывести(ПроцессорКомпоновки);	
	//Возвращаем полученную таблицу значений
	Возврат  Результат;	
КонецФункции

&НаСервере
Функция ПосчитатьИтогиНаСервере()
	ВсеЭлементы=СписокВКоллекциюЗначений();
	ЗадолженостьПоУведомлению=0;ОстатокЗадолженности=0;ТекущаяЗадолженость=0;	
	для каждого стр из ВсеЭлементы цикл
		ЗадолженостьПоУведомлению=ЗадолженостьПоУведомлению+стр.ЗадолженостьПоУведомлению;
		ОстатокЗадолженности=ОстатокЗадолженности+стр.ОстатокЗадолженности;
		ТекущаяЗадолженость=ТекущаяЗадолженость+стр.ТекущаяЗадолженость;
	КонецЦикла;	
	элементы.Список.ПодчиненныеЭлементы.ЗадолженостьПоУведомлению.ТекстПодвала=ЗадолженостьПоУведомлению;
	элементы.Список.ПодчиненныеЭлементы.ОстатокЗадолженности.ТекстПодвала=ОстатокЗадолженности;
	элементы.Список.ПодчиненныеЭлементы.ТекущаяЗадолженость.ТекстПодвала=ТекущаяЗадолженость;
КонецФункции

&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
	ПосчитатьИтогиНаСервере();
КонецПроцедуры

И вуаля, видим нечто подобное:

Nginx: настройка проксирования

Задача: есть локальный web сервис запущенный…ну например в докере. Не суть в общем где запущен. Может быть просто какой то локальный сервис типа web интерфейса к zigbee2mqtt: htpp://192.168.8.1:8080 Необходимо дать возможность открывать его в браузере, с нормальным ssl сертификатом ну и всё такое. Вот собственно для этого и нужно проксирование.

Решение: первым делом получим сертификат для домена. Для этого добавим в настройки nginx следующие строчки:

server {
        listen 80;
        server_name ваш_домен;
        root /var/www/m;
        index index.php;
}

После чего получим сертификат:

service nginx restart
certbot certonly --webroot -w /var/www/m -d ваш_домен

Далее настройки nginx изменим на:

server {
        listen 80;
        listen [::]:80;
        listen 443 ssl;
        server_name ваш_домен;
        if ($scheme = 'http') {return 301 https://$host$request_uri;}
        ssl_certificate     /etc/letsencrypt/live/ваш_домен/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/ваш_домен/privkey.pem;
        location / {
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_pass http://192.168.8.1:8080;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Real-IP $remote_addr;
        }
}

Что тут есть?

  1. Переадрессация с http на https
  2. Подсовывание сертификата
  3. Проксирование http://192.168.8.1:8080 на ваш_домен

Собственно и всё

1 2 3 314